<template>
  <div class="chat-container">
     <div class="chat-header">
      <button class="back-button" @click="goBack">
          <img src="@/assets/images/chatAI/back-icon.png" alt="back-icon" />
      </button>
      <h4>对话</h4>
      <img src="@/assets/images/chatAI/bg-time.png" alt="">
      <div class="chat-header-time">

      </div>
    </div>
    <div class="message-list" ref="messageList">
      <span>{{ currentTime }}</span>
     <!-- 猫咪卡片 -->
      <carArtCardVue/>

      <div
        v-for="(message, index) in messages"
        :key="index"
        class="message"
        :class="{ 'my-message': message.sender === 'me' }"
      >
        <div class="message-content">
          <div class="message-text" v-if="message.sender === 'me'">{{ message.text }}</div>
          <div class="message-text typing-effect" v-else v-html="message.text"></div>
        </div>
      </div>
    </div>

  </div>
  <div class="input-container">
      <img src="@/assets/images/chatAI/key-icon.png" alt="key-icon" class="key-icon" />
      <input
        type="text"
        v-model="newMessage"
        placeholder="开始探索未知的猫咪问题吧"
        @keyup.enter="sendMessage"
      />
      <button @click="sendMessage" class="button-with-icon">
          <img src="@/assets/images/chatAI/enter-icon.png" alt="enter-ico" />
      </button>
    </div>
</template>

<script setup>
import { marked } from 'marked';

defineOptions({
   name: 'ChatAI'
})

import carArtCardVue from "./components/carArtCard.vue";
import { ref, onMounted,reactive,onUnmounted} from "vue";
import { useRouter } from 'vue-router'
import {  uploadInput,getChatHistory} from './api/chat'
import axios from "axios";
import { useUserStore } from "@/stores/user";
const router = useRouter()
const goBack = () => {
router.push('/home');
}

const userStore = useUserStore();
const userId = userStore.userInfo.id;
// 响应式数据
const messages = ref([]);
const newMessage = ref([]);
const sendMessageData = reactive({
  userId:userId,
  question:'',
})
const currentTime = ref('');
// 更新时间函数
const updateTime = () => {
const date = new Date();
currentTime.value = date.toLocaleDateString('zh-CN', {
  month: '2-digit',
  day: '2-digit'
}) + ' ' +
date.toLocaleTimeString('zh-CN', {
  hour: '2-digit',
  minute: '2-digit'
});
};
// 消息输入框和发送按钮
const messageList = ref(null);

// 修改typeWithDelay函数，处理可能的乱码
const typeWithDelay = (text, element, delay = 30) => {
  // 如果文本为空，直接返回
  if (!text || text.length === 0) return;

  // 清除任何现有的打字定时器
  if (window.typingTimer) {
    clearTimeout(window.typingTimer);
  }

  // 尝试清理文本中的乱码字符
  const cleanText = text.replace(/[\uFFFD\uD800-\uDFFF]/g, '');

  // 获取当前文本长度作为起始位置
  const startPos = element.text.length;
  const fullText = cleanText;

  // 设置一个递归函数来逐字添加文本
  const typeChar = (pos) => {
    if (pos < fullText.length) {
      // 添加下一个字符
      const nextChar = fullText.charAt(pos);

      // 跳过可能的乱码字符
      if (nextChar.charCodeAt(0) >= 0xD800 && nextChar.charCodeAt(0) <= 0xDFFF) {
        typeChar(pos + 1);
        return;
      }

      element.text += nextChar;

      // 计算下一个字符的延迟时间（可以根据标点符号调整）
      let nextDelay = delay;
      if (['.', '!', '?', '。', '！', '？'].includes(nextChar)) {
        nextDelay = delay * 5; // 句子结束处停顿更长时间
      } else if ([',', ';', '，', '；'].includes(nextChar)) {
        nextDelay = delay * 3; // 逗号处停顿较长时间
      }

      // 滚动到底部
      scrollToBottom();

      // 设置下一个字符的定时器
      window.typingTimer = setTimeout(() => typeChar(pos + 1), nextDelay);
    }
  };

  // 开始打字效果
  typeChar(0);
};

// 移除特殊字符处理，直接返回原始输入
const sanitizeInput = (input) => input;

const sendMessage = () => {
  if (newMessage.value.trim()) {
    // 获取用户输入
    const userMessage = newMessage.value;

    messages.value.push({
      sender: "me",
      text: userMessage,
    });

    // 保存问题用于上传记录
    sendMessageData.question = userMessage;
    newMessage.value = "";

    // 添加一个空的回复消息，用于流式显示
    const replyIndex = messages.value.length;
    messages.value.push({
      sender: "other",
      text: "",
      isStreaming: true
    });

    scrollToBottom();

    // 为 Ollama 的 /api/generate 端点准备请求数据
    let data = {
      "model": "FelixAI-2-1:latest",
      "prompt": userMessage,
      "stream": true,
      "temperature": 0.7,
      "top_p": 0.9,
      "max_tokens": 2000
    };

    // 使用fetch API进行流式请求
    fetch('http://localhost:11434/api/generate', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(data)
    })
    .then(response => {
      const reader = response.body.getReader();
      let accumulatedResponse = "";

      function readStream() {
        return reader.read().then(({ done, value }) => {
          if (done) {
            // 流结束，保存完整对话记录
            // 如果缓冲区中还有内容，显示出来
            if (window.textBuffer && window.textBuffer.trim()) {
              // 将剩余内容添加到累积响应中
              accumulatedResponse += window.textBuffer;

              // 如果是第一次显示内容，使用打字效果
              if (messages.value[replyIndex].text === '') {
                simulateTyping(accumulatedResponse, messages.value[replyIndex]);
              } else {
                // 否则直接更新整个内容
                messages.value[replyIndex].text = formatStreamText(accumulatedResponse);
              }

              window.textBuffer = '';
            }

            uploadInput({
              userId: sendMessageData.userId,
              question: sendMessageData.question,
              answer: accumulatedResponse,
            }).then(res => {
              console.log(res);
            }).catch(err => {
              console.log(err);
            });

            // 移除打字光标效果
            messages.value[replyIndex].isStreaming = false;
            return;
          }

          // 解码收到的数据
          const chunk = new TextDecoder().decode(value);

          try {
            // 处理Ollama的响应
            const lines = chunk.split('\n').filter(line => line.trim() !== '');

            for (const line of lines) {
              try {
                const parsedLine = JSON.parse(line);

                // 从generate端点获取响应
                if (parsedLine.response) {
                  // 获取响应文本
                  let responseText = parsedLine.response;

                  // 过滤掉<think>标记和其他特殊标记
                  responseText = responseText
                    .replace(/<think>/g, '')
                    .replace(/<\/think>/g, '')
                    .replace(/&lt;think&gt;/g, '')
                    .replace(/&lt;\/think&gt;/g, '')
                    .replace(/amp;lt;think&gt;/g, '')
                    .replace(/amp;lt;\/think&gt;/g, '');

                  // 如果是空白字符或只有换行，跳过
                  if (!responseText.trim()) {
                    continue;
                  }

                  // 累积原始响应用于保存
                  accumulatedResponse += responseText;

                  // 收集文本后再显示，以实现更自然的打字效果
                  if (!window.textBuffer) {
                    window.textBuffer = '';
                  }

                  // 将新文本添加到缓冲区
                  window.textBuffer += responseText;

                  // 当缓冲区达到一定大小或收到句号等标点符号时，显示文本
                  if (window.textBuffer.length >= 20 ||
                      ['.', '!', '?', '。', '！', '？', '，', '；', ',', ';', '\n'].some(punct => window.textBuffer.includes(punct))) {

                    // 如果是第一次显示内容，使用打字效果
                    if (messages.value[replyIndex].text === '') {
                      simulateTyping(window.textBuffer, messages.value[replyIndex]);
                    } else {
                      // 否则直接更新整个内容
                      messages.value[replyIndex].text = formatStreamText(accumulatedResponse);
                    }

                    scrollToBottom();

                    // 清空缓冲区
                    window.textBuffer = '';
                  }
                }
              } catch (e) {
                console.error('Error parsing JSON:', e);
              }
            }
          } catch (e) {
            console.error('Error processing chunk:', e);
          }

          // 继续读取流
          return readStream();
        });
      }

      return readStream();
    })
    .catch(err => {
      console.error('Fetch error:', err);
      // 错误处理：显示错误消息
      messages.value[replyIndex].text = "抱歉，发生了错误，请稍后再试。";
      messages.value[replyIndex].isError = true;
    });
  }
};

// 修改formatStreamText函数，修复HTML转义问题
const formatStreamText = (text) => {
  if (!text) return '';

  try {
    // 先过滤掉特殊标记和已转义的HTML标签
    let cleanedText = text
      // 移除<think>标签
      .replace(/<think>/g, '')
      .replace(/<\/think>/g, '')
      // 移除已转义的<think>标签
      .replace(/&lt;think&gt;/g, '')
      .replace(/&lt;\/think&gt;/g, '')
      .replace(/amp;lt;think&gt;/g, '')
      .replace(/amp;lt;\/think&gt;/g, '')
      // 修复常见的HTML实体问题
      .replace(/&amp;lt;/g, '&lt;')
      .replace(/&amp;gt;/g, '&gt;')
      .replace(/&amp;amp;/g, '&amp;')
      .replace(/&amp;quot;/g, '&quot;')
      .replace(/&amp;#39;/g, '&#39;')
      .replace(/&amp;nbsp;/g, '&nbsp;');

    // 然后转义HTML特殊字符，但避免重复转义
    // 检查文本是否已经包含HTML实体
    const hasEntities = /&[a-z]+;/i.test(cleanedText);

    let escaped;
    if (hasEntities) {
      // 如果已经包含HTML实体，尝试解码后再重新编码
      const tempDiv = document.createElement('div');
      tempDiv.innerHTML = cleanedText;
      const decodedText = tempDiv.textContent;

      escaped = decodedText
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;');
    } else {
      // 如果没有HTML实体，直接转义
      escaped = cleanedText
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;');
    }

    // 配置marked选项
    marked.setOptions({
      highlight: function(code) {
        return code;
      },
      langPrefix: 'language-',
      gfm: true,
      breaks: true,
      sanitize: false,
      smartypants: false
    });

    // 自定义渲染器
    const renderer = new marked.Renderer();
    renderer.code = function(code, language) {
      language = language || 'text';
      return `<pre data-language="${language}"><code class="language-${language}">${code}</code></pre>`;
    };

    // 使用marked解析Markdown
    return marked.parse(escaped, { renderer });
  } catch (e) {
    console.error('Error parsing markdown:', e);
    // 如果解析失败，返回简单的HTML转义文本
    return text
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/\n/g, '<br>');
  }
};

const scrollToBottom = () => {
if (messageList.value) {
  messageList.value.scrollTop = messageList.value.scrollHeight;
}
};

const timer = setInterval(updateTime, 60000); // 每分钟更新一次
// 页面加载完成后滚动到底部
onMounted(() => {
  updateTime(); // 初始化时间

  // 添加代码块滚动检测
  const checkCodeBlocksOverflow = () => {
    const codeBlocks = document.querySelectorAll('.message-text pre');
    codeBlocks.forEach(block => {
      if (block.scrollWidth > block.clientWidth) {
        block.classList.add('scrollable');
      } else {
        block.classList.remove('scrollable');
      }
    });
  };

  // 监听消息变化，检查代码块溢出
  const observer = new MutationObserver(checkCodeBlocksOverflow);
  observer.observe(messageList.value, { childList: true, subtree: true });

  // 初始检查
  setTimeout(checkCodeBlocksOverflow, 500);

  //获取历史记录前判断是否登录
  if(!userId){
    console.log('未登录');

  }else{
  getChatHistory({userId:userId}).then(res =>{
    console.log(res.data);
    const dataArray = res.data.data.reverse(); // 对历史记录进行反转
    dataArray.forEach(item => {
      var answer ={
        sender:'other',
        text:item.answer,
      }
      var question ={
        sender:'me',
        text:item.question,
      }
      messages.value.push(question);
      messages.value.push(answer);

    });
  scrollToBottom();
  });
  }
});
onUnmounted(() => {
clearInterval(timer);
});

// 添加一个新的函数，用于模拟更慢的打字效果
const simulateTyping = (text, element) => {
  // 清除任何现有的打字定时器
  if (window.typingTimer) {
    clearTimeout(window.typingTimer);
  }

  // 格式化文本
  const formattedText = formatStreamText(text);

  // 设置初始文本
  element.text = '';

  // 创建一个临时元素来解析HTML
  const tempDiv = document.createElement('div');
  tempDiv.innerHTML = formattedText;
  const plainText = tempDiv.textContent || tempDiv.innerText || '';

  // 设置打字速度（毫秒/字符）
  const typingSpeed = 100; // 更慢的打字速度

  // 计算总时间
  const totalTime = plainText.length * typingSpeed;

  // 如果文本太长，使用更快的速度
  const adjustedTime = Math.min(totalTime, 5000); // 最多5秒

  // 使用CSS动画来模拟打字效果
  element.typingAnimation = true;

  // 直接设置最终文本，但使用CSS动画来控制显示速度
  setTimeout(() => {
    element.text = formattedText;

    // 动画结束后移除标记
    setTimeout(() => {
      element.typingAnimation = false;
    }, adjustedTime);
  }, 10);
};
</script>


<style lang="scss" scoped>
$primary-purple: #8a56e8; // 主紫色
$light-purple: #f0e8ff;   // 浅紫色背景
$dark-purple: #6a3dd3;    // 深紫色
$input-bg-color: #ffffff;
$text-color: #333333;
$light-gray: #f5f5f5;
$border-radius: 20px;

.chat-container {
  max-width: 100%;
  width: 100%;
  height: 100vh;
  margin: 0;
  padding: 0 0 70px 0;
  overflow: hidden;
  background: $light-purple;
  display: flex;
  flex-direction: column;
  position: relative;

  /* 聊天头部样式 */
  .chat-header {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 15px 0;
    background: $primary-purple;
    color: white;
    border-bottom-left-radius: $border-radius;
    border-bottom-right-radius: $border-radius;
    box-shadow: 0 4px 10px rgba(138, 86, 232, 0.2);
    z-index: 10;

    h4 {
      margin: 0;
      font-size: 18px;
      font-weight: 600;
      text-align: center;
    }

    img {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      opacity: 0.2;
      z-index: -1;
    }

    .back-button {
      position: absolute;
      left: 15px;
      top: 50%;
      transform: translateY(-50%);
      background: none;
      border: none;
      cursor: pointer;
      width: 32px;
      height: 32px;
      display: flex;
      align-items: center;
      justify-content: center;

      img {
        width: 20px;
        height: 20px;
        position: static;
        transform: none;
        opacity: 1;
        filter: brightness(0) invert(1);
      }
    }
  }

  /* 消息列表样式 */
  .message-list {
    flex: 1;
    width: 100%;
    padding: 20px 10px 80px 10px; /* 减少左右内边距 */
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    scroll-behavior: smooth;
    background-image: linear-gradient(to bottom, rgba(138, 86, 232, 0.05), rgba(138, 86, 232, 0.1));

    span {
      display: block;
      text-align: center;
      color: #666;
      font-size: 12px;
      background: rgba(255, 255, 255, 0.7);
      padding: 4px 12px;
      border-radius: 15px;
      width: fit-content;
      margin: 10px auto;
      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
    }

    /* 消息样式 */
    .message {
      margin: 8px 0;
      display: flex;
      width: 100%;
      padding: 0 5px;
      animation: fadeIn 0.3s ease-in-out;
    }

    .my-message {
      justify-content: flex-end;
    }

    .message-content {
      max-width: 85%;
      padding: 10px 14px;
      margin: 0;
      border-radius: 18px;
      background-color: white;
      position: relative;
      box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
      transition: all 0.3s ease;
      overflow: hidden;
    }

    .my-message .message-content {
      background-color: $primary-purple;
      color: white;
      border-bottom-right-radius: 4px;
    }

    .message:not(.my-message) .message-content {
      border-bottom-left-radius: 4px;
    }

    .message-text {
      font-size: 14px;
      line-height: 1.4;
      word-break: break-word;
      white-space: pre-wrap;
      max-width: 100%;
      overflow-wrap: break-word;

      /* 增强代码块样式 */
      & pre {
        background-color: #f6f8fa;
        padding: 8px;
        border-radius: 5px;
        margin: 8px 0;
        max-width: 100%;
        overflow-x: auto;
        position: relative;
        font-family: 'Courier New', Courier, monospace;
        border: 1px solid #e1e4e8;

        /* 添加语言标识和复制按钮的容器 */
        &::before {
          content: attr(data-language);
          position: absolute;
          top: 0;
          right: 0;
          padding: 2px 7px;
          font-size: 10px;
          color: #666;
          background: #e1e4e8;
          border-bottom-left-radius: 4px;
          font-family: sans-serif;
          opacity: 0.7;
        }

        & code {
          background-color: transparent;
          padding: 0;
          font-size: 12px;
          display: block;
          line-height: 1.5;
          color: #24292e;
          overflow-x: auto;
          white-space: pre;
          word-break: normal;

          /* 为不同语法添加颜色 */
          .keyword { color: #d73a49; }
          .string { color: #032f62; }
          .comment { color: #6a737d; }
          .function { color: #6f42c1; }
          .number { color: #005cc5; }
        }
      }

      /* 行内代码样式 */
      & :not(pre) > code {
        font-family: 'Courier New', Courier, monospace;
        background-color: rgba(27, 31, 35, 0.05);
        padding: 2px 4px;
        border-radius: 3px;
        font-size: 12px;
        color: #e83e8c;
        word-break: break-word;
        white-space: normal;
      }
    }
  }
}

/* 输入容器样式 */
.input-container {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px; /* 减少间距 */
  padding: 12px 10px; /* 减少内边距 */
  background-color: white;
  box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
  z-index: 100;
  height: 70px; /* 减小高度 */

  .key-icon {
    width: 24px;
    height: 24px;
    filter: invert(42%) sepia(93%) saturate(1352%) hue-rotate(233deg) brightness(87%) contrast(87%);
  }

  input {
    flex: 1;
    height: 40px; /* 减小高度 */
    padding: 0 15px; /* 减少内边距 */
    font-size: 14px; /* 减小字体 */
    border: 1px solid rgba(138, 86, 232, 0.3);
    border-radius: 20px;
    outline: none;
    background: #f8f5ff;
    transition: all 0.3s ease;

    &:focus {
      border-color: $primary-purple;
      box-shadow: 0 0 0 2px rgba(138, 86, 232, 0.1);
    }

    &::placeholder {
      color: #aaa;
    }
  }

  button {
    width: 40px; /* 减小尺寸 */
    height: 40px; /* 减小尺寸 */
    border-radius: 50%;
    background: $primary-purple;
    border: none;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.2s ease;

    &:hover {
      background: $dark-purple;
      transform: scale(1.05);
    }

    &:active {
      transform: scale(0.95);
    }

    img {
      width: 18px;
      height: 18px;
      filter: brightness(0) invert(1);
    }
  }
}

/* 添加打字动画效果 */
@keyframes typing {
  from { opacity: 0; }
  to { opacity: 1; }
}

.typing-effect {
  position: relative;
  animation: typing 1.5s ease-out;
}

/* 动画效果 */
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

/* 确保空消息不会显示 */
.message-content:empty {
  display: none;
}

.message-text:empty {
  display: none;
}

/* 响应式调整 */
@media (max-width: 375px) {
  /* iPhone SE 特定调整 */
  .chat-container {
    width: 100vw;
    overflow-x: hidden;
  }

  .message-list {
    padding: 15px 8px 70px 8px;
  }

  .message-content {
    max-width: 90%;
    padding: 8px 12px;
  }

  .input-container {
    padding: 10px 8px;
    height: 60px;
  }

  .input-container .key-icon {
    width: 24px;
    height: 24px;
  }

  .input-container input {
    height: 38px;
    font-size: 13px;
  }

  .input-container button {
    width: 38px;
    height: 38px;
  }

  .input-container button img {
    width: 18px;
    height: 18px;
  }
}

/* 滚动条样式 */
.message-list::-webkit-scrollbar {
  width: 6px;
}

.message-list::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.1);
}

.message-list::-webkit-scrollbar-thumb {
  background-color: rgba(138, 86, 232, 0.3);
  border-radius: 3px;
}

/* 为代码块添加水平滚动指示器 */
.message-text pre {
  position: relative;

  &.scrollable::after {
    content: '';
    position: absolute;
    bottom: 0;
    right: 0;
    height: 100%;
    width: 20px;
    background: linear-gradient(to right, rgba(246, 248, 250, 0), rgba(246, 248, 250, 1));
    pointer-events: none;
  }
}

/* 为我的消息中的代码块调整颜色 */
.my-message .message-text {
  & pre {
    background-color: rgba(255, 255, 255, 0.1);
    border-color: rgba(255, 255, 255, 0.2);

    & code {
      color: #f8f8f2;
    }

    &::before {
      background: rgba(255, 255, 255, 0.2);
      color: #fff;
    }
  }

  & :not(pre) > code {
    background-color: rgba(255, 255, 255, 0.2);
    color: #fff;
  }
}
</style>
